/**
  @file
  @author Stefan Frings
*/

#include "filelogger.h"
#include <QTime>
#include <QStringList>
#include <QThread>
#include <QtGlobal>
#include <QFile>
#include <QTimerEvent>
#include <QDir>
#include <QFileInfo>
#include <stdio.h>

using namespace stefanfrings;

void FileLogger::refreshSettings()
{
    mutex.lock();
    // Save old file name for later comparision with new settings
    QString oldFileName=fileName;

    // Load new config settings
    settings->sync();
    fileName=settings->value("fileName").toString();
    // Convert relative fileName to absolute, based on the directory of the config file.
#ifdef Q_OS_WIN32
    if (QDir::isRelativePath(fileName) && settings->format()!=QSettings::NativeFormat)
#else
    if (QDir::isRelativePath(fileName))
#endif
    {
        QFileInfo configFile(settings->fileName());
        fileName=QFileInfo(configFile.absolutePath(),fileName).absoluteFilePath();
    }
    maxSize=settings->value("maxSize",0).toLongLong();
    maxBackups=settings->value("maxBackups",0).toInt();
    msgFormat=settings->value("msgFormat","{timestamp} {type} {msg}").toString();
    timestampFormat=settings->value("timestampFormat","yyyy-MM-dd hh:mm:ss.zzz").toString();
    minLevel=static_cast<QtMsgType>(settings->value("minLevel",0).toInt());
    bufferSize=settings->value("bufferSize",0).toInt();

    // Create new file if the filename has been changed
    if (oldFileName!=fileName)
    {
        fprintf(stderr,"Logging to %s\n",qPrintable(fileName));
        close();
        open();
    }
    mutex.unlock();
}


FileLogger::FileLogger(QString log_file, const int refreshInterval, QObject* parent)
    : Logger(parent)
{
    Q_ASSERT(settings!=0);
    Q_ASSERT(refreshInterval>=0);
    this->settings=settings;
    file=0;
    if (refreshInterval>0)
    {
		connect(&refreshTimer,SIGNAL(timeout()),this,SLOT(onTimerEvent()));
        //refreshTimer.start(refreshInterval);
    }
	connect(&flushTimer,SIGNAL(timeout()),this,SLOT(onTimerEvent()));
    //flushTimer.start(1000);
    //refreshSettings();
	
	fileName = log_file;
	maxSize = 0;
    maxBackups = 0;
    msgFormat = "{timestamp} {type} {msg}";
    timestampFormat = "yyyy-MM-dd hh:mm:ss.zzz";  
    bufferSize = 0;
	open();
}


FileLogger::~FileLogger()
{
    close();
}


void FileLogger::write(const LogMessage* logMessage)
{
    // Try to write to the file
    if (file)
    {
        // Write the message
        fprintf(file,"%s",qPrintable(logMessage->toString(msgFormat,timestampFormat)));

        // Flush error messages immediately, to ensure that no important message
        // gets lost when the program terinates abnormally.
        if (logMessage->getType()>=QtCriticalMsg)
        {
            fflush(file);
        }

        // Check for success
        if (ferror(file))
        {
            close();
            qWarning("Cannot write to log file %s:%d",qPrintable(fileName),ferror(file));
        }

    }

    // Fall-back to the super class method, if writing failed
    if (!file)
    {
        Logger::write(logMessage);
    }

}

void FileLogger::open()
{
    if (fileName.isEmpty())
    {
        qWarning("Name of logFile is empty");
    }
    else {
		file = fopen(fileName.toStdString().c_str(),"wt");
        if(!file)
        {
            qWarning("Cannot open log file %s: %d",qPrintable(fileName),ferror(file));
            file = NULL;
        }
    }
}


void FileLogger::close()
{
    if (file)
    {
        fclose(file);
        file = NULL;        
    }
}

void FileLogger::rotate() {
    // count current number of existing backup files
    int count=0;
    forever
    {
        QFile bakFile(QString("%1.%2").arg(fileName).arg(count+1));
        if (bakFile.exists())
        {
            ++count;
        }
        else
        {
            break;
        }
    }

    // Remove all old backup files that exceed the maximum number
    while (maxBackups>0 && count>=maxBackups)
    {
        QFile::remove(QString("%1.%2").arg(fileName).arg(count));
        --count;
    }

    // Rotate backup files
    for (int i=count; i>0; --i) {
        QFile::rename(QString("%1.%2").arg(fileName).arg(i),QString("%1.%2").arg(fileName).arg(i+1));
    }

    // Backup the current logfile
    QFile::rename(fileName,fileName+".1");
}


void FileLogger::onTimerEvent()
{
	QTimer *timer = qobject_cast<QTimer*>(sender());
    
	if (timer == &refreshTimer)
    {
        refreshSettings();
    }
    else if (timer == &flushTimer && file)
    {
        mutex.lock();

        // Flush the I/O buffer
        fflush(file);

        // Rotate the file if it is too large
        /*if (maxSize>0) && file->size()>=maxSize)
        {
            close();
            rotate();
            open();
        }
		*/
        mutex.unlock();
    }
}
